// 蜂窝蜜造平台生成代码，如手工更改，请添加到 .beeignore 忽略生成

package com.fowo.api.datainterface.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.level.Level;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fowo.api.common.model.JoinResult;
import com.fowo.api.common.query.QueryGenerator;
import com.fowo.api.datainterface.constants.Constants;
import com.fowo.api.datainterface.constants.DataTypeKind;
import com.fowo.api.datainterface.constants.DatainterfaceTypeKind;
import com.fowo.api.datainterface.entity.DatainterfaceLog;
import com.fowo.api.datainterface.mapper.DatainterfaceLogMapper;
import com.fowo.api.datainterface.model.DatainterfaceLogSearchParamPo;
import com.fowo.api.datainterface.model.DatainterfaceLogVo;
import com.fowo.api.datainterface.service.DatainterfaceLogService;
import com.fowo.api.datainterface.service.DatainterfaceService;
import com.fowo.api.datainterface.util.JsonUtil;
import com.fowo.api.sys.service.FileService;
import com.fowo.api.sys.service.SysImportTemplateService;
import com.fowo.api.user.model.JwtUserInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.Validator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 数据接口调用日志 服务实现基类
 */
@Service
@Slf4j
@DS("ds21")
public class DatainterfaceLogServiceImpl
        extends ServiceImpl<DatainterfaceLogMapper, DatainterfaceLog>
        implements DatainterfaceLogService {

    public static final Map<String, String> SORT_FIELD_MAP = new HashMap<>();
    // 导出时单次查询最大记录数
    protected static final int EXPORT_QUERY_MAX_SIZE = 1000;
    // 支持导出的最大记录数(1048576 为 Excel 支持的最大行数)
    protected static final long EXPORT_MAX_SIZE = 1048575;

    @Resource
    protected FileService fileService;

    @Resource
    protected SysImportTemplateService importTemplateService;

    @Resource
    protected Validator validator;



    @Resource
    private DatainterfaceService datainterfaceService;

    private static final Pattern PATTERN = Pattern.compile("\\d+");
    /**
     * 创建数据接口调用日志
     *
     * @param model 数据接口调用日志
     * @return 新数据的主键
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long create(DatainterfaceLogVo model) throws Exception {
        JwtUserInfo currentUser = JwtUserInfo.fromHeader();
        DatainterfaceLog entity = new DatainterfaceLog();
        BeanUtils.copyProperties(model, entity);
        entity.setCreateTime(new Date());
        entity.setLastUpdateTime(new Date());
        if (currentUser != null) {
            entity.setCreateUser(currentUser.getUserId());
            entity.setLastUpdateUser(currentUser.getUserId());
        }
        if (this.save(entity)) {
            return entity.getId();
        }
        throw new Exception("数据接口调用日志保存失败");
    }

    /**
     * 更新数据接口调用日志
     *
     * @param model 数据接口调用日志
     * @return 更新是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(DatainterfaceLogVo model) throws Exception {
        JwtUserInfo currentUser = JwtUserInfo.fromHeader();
        DatainterfaceLog entity = this.getById(model.getId());
        if (entity == null) {
            throw new Exception("数据接口调用日志不存在");
        }
        BeanUtils.copyProperties(
                model,
                entity,
                "id",
                "createTime",
                "createUser",
                "lastUpdateTime",
                "lastUpdateUser"
        );
        entity.setLastUpdateTime(new Date());
        if (currentUser != null) {
            entity.setLastUpdateUser(currentUser.getUserId());
        }
        if (this.updateById(entity)) {
            return true;
        }
        return false;
    }

    /**
     * 更新数据接口调用日志（带空值）
     *
     * @param model 数据接口调用日志
     * @return 更新是否成功
     */

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateForEdit(DatainterfaceLogVo model) throws Exception {
        JwtUserInfo currentUser = JwtUserInfo.fromHeader();
        DatainterfaceLog entity = this.getById(model.getId());
        if (entity == null) {
            throw new Exception("数据接口调用日志不存在");
        }
        model.setLastUpdateTime(new Date());
        if (currentUser != null) {
            model.setLastUpdateUser(currentUser.getUserId());
        }
        boolean isOk = new LambdaUpdateChainWrapper<>(baseMapper)
                .set(DatainterfaceLog::getLastUpdateTime, model.getLastUpdateTime())
                .set(DatainterfaceLog::getLastUpdateUser, model.getLastUpdateUser())
                .set(DatainterfaceLog::getLogType, model.getLogType())
                .set(DatainterfaceLog::getBusinessId, model.getBusinessId())
                .set(DatainterfaceLog::getBusinessKeywords, model.getBusinessKeywords())
                .set(DatainterfaceLog::getBusinessTime, model.getBusinessTime())
                .set(DatainterfaceLog::getBusinessType, model.getBusinessType())
                .set(DatainterfaceLog::getInvokWasteTime, model.getInvokWasteTime())
                .set(DatainterfaceLog::getExceptionContent, model.getExceptionContent())
                .set(DatainterfaceLog::getDescriptions, model.getDescriptions())
                .eq(DatainterfaceLog::getId, model.getId())
                .update();
        if (isOk) {
        }
        return isOk;
    }

    /**
     * 删除数据接口调用日志
     *
     * @param id 数据接口调用日志的主键
     * @return 删除是否成功
     */
    @Override
    public boolean delete(Long id) throws Exception {
        return this.removeById(id);
    }

    /**
     * 批量删除数据接口调用日志
     *
     * @param ids 数据接口调用日志的主键列表
     * @return 删除是否成功
     */
    @Override
    public boolean batchDelete(List<Long> ids) throws Exception {
        return baseMapper.deleteBatchIds(ids) > 0;
    }


    /**
     * 获取详情
     *
     * @param id 数据接口调用日志的主键
     */
    @Override
    public DatainterfaceLogVo getVoById(Long id) throws Exception {
        DatainterfaceLog vo = this.getById(id);
        if (vo == null) {
            return null;
        }
        return BeanUtil.copyProperties(vo, DatainterfaceLogVo.class);
    }

    /**
     * 分页查询数据接口调用日志
     *
     * @param search 查询条件
     * @return 数据接口调用日志分页查询结果
     */
    @Override
    public Page<DatainterfaceLog> pageSearch(
            DatainterfaceLogSearchParamPo search
    ) {
        DatainterfaceLog datainterfaceLog = BeanUtil.copyProperties(search, DatainterfaceLog.class);
        QueryWrapper<DatainterfaceLog> queryWrapper = QueryGenerator.initQueryWrapper(datainterfaceLog, search);
        Page<DatainterfaceLog> pageList = this.page(search.toPage(), queryWrapper);
        return pageList;

    }
    /**
     * 通过删除标记查询数据接口调用日志主键(重复时返回最新的主键)
     */
    @Override
    public Long getIdByDelFlag(String delFlag) {
        return this.getObj(Wrappers.<DatainterfaceLog>lambdaQuery().select(DatainterfaceLog::getId).eq(DatainterfaceLog::getDelFlag, delFlag), res -> Convert.toLong(res));
    }

    /**
     * 通过删除标记查询数据接口调用日志多主键(重复时返回最新的主键)
     */
    @Override
    public List<Long> getIdsByDelFlag(List<String> list) {
        return this.listObjs(Wrappers.<DatainterfaceLog>lambdaQuery().select(DatainterfaceLog::getId).in(DatainterfaceLog::getDelFlag, list), res -> Convert.toLong(res));
    }

    /**
     * 通过数据接口调用日志主键查询删除标记
     */
    @Override
    public String getDelFlagById(Long id) {
        return this.getObj(Wrappers.<DatainterfaceLog>lambdaQuery().select(DatainterfaceLog::getDelFlag).eq(DatainterfaceLog::getId, id), res -> Convert.toStr(res));
    }

    /**
     * 通过数据接口调用日志主键查询删除标记列表
     */
    @Override
    public List<String> getDelFlagByIds(List<Long> ids) {
        return this.listObjs(Wrappers.<DatainterfaceLog>lambdaQuery().select(DatainterfaceLog::getDelFlag).in(DatainterfaceLog::getId, ids), res -> Convert.toStr(res));
    }

    /**
     * 列表查询数据接口调用日志
     *
     * @param search 查询条件
     * @return 数据接口调用日志列表查询结果
     */
    @Override
    public List<DatainterfaceLog> search(
            DatainterfaceLogSearchParamPo search
    ) {
        DatainterfaceLog datainterfaceLog = BeanUtil.copyProperties(search, DatainterfaceLog.class);
        QueryWrapper<DatainterfaceLog> queryWrapper = QueryGenerator.initQueryWrapper(datainterfaceLog, search);
        return this.list(queryWrapper);
    }

    /**
     * 查询数据接口调用日志最后更新时间
     *
     * @param search 查询条件
     * @return 数据接口调用日志最后更新时间
     */
    @Override
    public Date searchLastUpdateTime(DatainterfaceLogSearchParamPo search) {
        DatainterfaceLog datainterfaceLog = BeanUtil.copyProperties(search, DatainterfaceLog.class);
        QueryWrapper<DatainterfaceLog> queryWrapper = QueryGenerator.initQueryWrapper(datainterfaceLog, search, null, null);
        queryWrapper.select("max(last_update_time) last_update_time");
        return this.getObj(queryWrapper, res -> Convert.toDate(res));
    }





    /**
     * dataError错误重试
     *
     * @param ids
     * @return
     */
    @Override
    public String retryInvokeToBatch(List<Long> ids, String sql) {
        try {
            List<DatainterfaceLog> list = null;
            if (StrUtil.isNotBlank(sql)) {
                LambdaQueryWrapper<DatainterfaceLog> dw = new LambdaQueryWrapper<DatainterfaceLog>().inSql(DatainterfaceLog::getId, sql);
                list = this.list(dw);
            } else {
                Assert.isTrue(CollUtil.isNotEmpty(ids), "未找到参数信息，请检查");
                list = listByIds(ids);
            }
            Assert.isTrue(CollUtil.isNotEmpty(list), "未找到对应数据，请检查");
            StrBuilder strBuilder = StrUtil.strBuilder();
            double i = 1;
            for (DatainterfaceLog entity : list) {
                list.indexOf(entity);
                JoinResult joinResult = this.retryInvokeTo(entity);
                if (i > 1) {
                    strBuilder.append(" ; ");
                }
                if (!joinResult.isSuccess()) {
                    strBuilder.append(StrUtil.format("错误{}:ID:{},路径:{},参数:{},信息：{}", Convert.numberToChinese(i, false), entity.getId(), entity.getUrl(), entity.getRequestContent(), joinResult.getVal()));
                } else {
                    strBuilder.append(StrUtil.format("成功{}:ID:{},路径:{},参数:{},信息：{}", Convert.numberToChinese(i, false), entity.getId(), entity.getUrl(), entity.getRequestContent(), joinResult.getVal()));
                }
                i++;
            }
            return StrUtil.isBlank(strBuilder.toString()) ? "全部执行成功！" : strBuilder.toString();
        } catch (Exception ex) {
            return StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000);
        }
    }
    /**
     * dataError错误重试
     *
     * @param entity
     * @return
     */
    private JoinResult retryInvokeTo(DatainterfaceLog entity) {
        try {
            Assert.isTrue(StrUtil.isAllNotBlank(entity.getUrl()), "单据验证错误！");
            Object retry = datainterfaceService.executeInterfaceByContextretry(entity);
            String businessKeywords = null;
            if (StrUtil.isEmpty(entity.getBusinessKeywords())) {
                businessKeywords = StrUtil.concat(true, Constants.retry + 1 + "次");
            } else {
                try {
                    Matcher matcher = PATTERN.matcher(entity.getBusinessKeywords());
                    if (matcher.find()) {
                        int num = Integer.parseInt(matcher.group());
                        StrUtil.concat(true, Constants.retry + (++num) + "次");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            entity.setBusinessKeywords(businessKeywords);
            updateById(entity);
            return JoinResult.success(retry);
        } catch (Exception ex) {
            return JoinResult.fail(StrUtil.subPre(ExceptionUtil.getRootCauseMessage(ex), 2000));
        }
    }


    /**
     * 记录异常日志
     *
     * @param businessId
     * @param businessKeywords
     * @param businessType
     * @param data
     */
    public void doRecordLog(String businessId, String businessKeywords, String businessType, String data) {
        try {
            Assert.isTrue(StrUtil.isAllNotBlank(businessId, businessKeywords, businessType, data), "参数不为空！");
            Assert.isTrue(EnumUtil.contains(DataTypeKind.class, businessType), "数据类型不存在");
            DatainterfaceLog entity = new DatainterfaceLog();
            entity.setBusinessId(businessId);
            entity.setLogType("INFO");
            entity.setBusinessKeywords(businessKeywords);
            entity.setBusinessTime(DateUtil.now());
            entity.setBusinessType(businessType);
            entity.setLogData(data);
            entity.setInvokWasteTime(0L);
            create(entity);
        } catch (Exception ex) {
            log.error("日志记录错误,错误信息：" + ex.getMessage());
        }
    }



    /**
     * 处理请求日志，记录执行过程报错
     *
     * @param entity
     */
    public void create(DatainterfaceLog entity) {
        Assert.isTrue(ObjectUtil.isNotEmpty(entity) && StrUtil.isAllNotBlank(entity.getLogType()), "日志参数不为空");
        JwtUserInfo currentUser = JwtUserInfo.fromHeader();
        entity.setCreateTime(new Date());
        entity.setLastUpdateTime(new Date());
        entity.setDelFlag(false);
        if (currentUser != null) {
            entity.setCreateUser(currentUser.getUserId());
            entity.setLastUpdateUser(currentUser.getUserId());
        }
        this.save(entity);
    }

    /**
     * 记录三方日志
     *
     * @param entity
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void writeLog(DatainterfaceLog entity) {
        try {
            Assert.isTrue(ObjectUtil.isNotEmpty(entity)
                    && StrUtil.isAllNotBlank(entity.getBusinessType(), entity.getMethod()), "参数不为空！");
            if (StrUtil.isNotBlank(entity.getLogType())) {
                entity.setLogType(Level.INFO.name());
            }
            if (ObjectUtil.isNotEmpty(entity.getBusinessTime())) {
                entity.setBusinessTime(DateUtil.now());
            }
            JwtUserInfo currentUser = JwtUserInfo.fromHeader();
            entity.setCreateTime(new Date());
            entity.setLastUpdateTime(new Date());
            entity.setDelFlag(false);
            if (currentUser != null) {
                entity.setCreateUser(currentUser.getUserId());
                entity.setLastUpdateUser(currentUser.getUserId());
            }
            this.save(entity);
        } catch (Exception ex) {
            log.error("日志记录错误,错误信息：" + ex.getMessage());
        }
    }

    /**
     * 处理请求日志，记录映射错误数据
     *
     * @param logModelList
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void createBatch(List<DatainterfaceLog> logModelList) {
        if (CollUtil.isNotEmpty(logModelList)) {
            JwtUserInfo currentUser = JwtUserInfo.fromHeader();
            for (DatainterfaceLog entity : logModelList) {
                Assert.isTrue(ObjectUtil.isNotEmpty(entity) && StrUtil.isAllNotBlank(entity.getLogType()), "日志参数不为空");
                entity.setCreateTime(new Date());
                entity.setLastUpdateTime(new Date());
                entity.setDelFlag(false);
                if (currentUser != null) {
                    entity.setCreateUser(currentUser.getUserId());
                    entity.setLastUpdateUser(currentUser.getUserId());
                }
            }
            this.saveBatch(logModelList);
        }
    }


    /**
     * builderLog 日志的基础构造
     *
     * @param businessType
     * @return
     */
    @Override
    public DatainterfaceLog builderLog(String businessType, String url, String method, Object params, Object headers, String descriptions) {
        DatainterfaceLog builderLog = DatainterfaceLog.builder()
                .url(url)
                .method(method)
                .requestContent(JsonUtil.getObjectToString(params))
                .requestHeaders(JsonUtil.getObjectToString(headers))
                .businessType(businessType)
                .logType(Level.INFO.name())
                .businessTime(DateUtil.now())
                .descriptions(descriptions)
                .responseStatus("200").build();
        builderLog.setOrientation(StrUtil.isNotBlank(builderLog.getOrientation()) ? builderLog.getOrientation() : DatainterfaceTypeKind.To.getValue());
        return builderLog;
    }
}
